:- module(m_tree234).
:- export tree234_to_assoc_list / 2.
:- export assoc_list_to_tree234 / 2.
:- export count / 2.
:- export update / 4.
:- export values / 2.
:- export keys / 2.
:- export remove_smallest / 4.
:- export remove / 4.
:- export delete / 3.
:- export set / 4.
:- export insert / 4.
:- export upper_bound_lookup / 4.
:- export upper_bound_search / 4.
:- export lower_bound_lookup / 4.
:- export lower_bound_search / 4.
:- export lookup / 3.
:- export search / 3.
:- export member / 3.
:- export is_empty / 1.
:- export init / 1.
:- comment(summary, "A map (dictionary) implemented using 2-3-4 trees").
:- comment(author, "Thomas Conway (Mercury) and Warwick Harvey (ECLiPSe)").
:- comment(desc, html("\t<P>\n\tThis module implements 2-3-4 trees.  They can be used to manage and\n\tindex a collection of key/value pairs.  You probably want to use the\n\tinterface provided by `map.pl' instead of using this module\n\tdirectly.\n\t</P>\n\t<P>\n\tNote that keys must be ground, but values are allowed to be\n\tvariables.\n\t</P>\n\t")).
:- comment(assoc_list_to_tree234 / 2, [amode : assoc_list_to_tree234(+, -), args : ["AssocList" : "A list of key-value pairs", "Tree" : "A 2-3-4 tree"], summary : "Converts an association list into a tree.", fail_if : "Never fails.", resat : no, see_also : [tree234_to_assoc_list / 2], desc : html("\t<P>\n\tAssocList is a list of key/value pairs of the form Key-Value,\n\tand Tree is a tree containing these key/value pairs.  If a key\n\tappears more than once in AssocList, then its corresponding value\n\tin the tree Tree will be the last one appearing in AssocList.\n\t</P>\n\t")]).
:- comment(count / 2, [amode : count(+, ?), args : ["Tree" : "A 2-3-4 tree", "Count" : "The number of elements in Tree"], summary : "Count the number of elements in a tree.", fail_if : "Fails if Count does not unify with the number of elements in Tree.", resat : no, desc : html("\t<P>\n\tCounts the number of elements in the tree Tree, and attempts to\n\tunify the result with Count.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(delete / 3, [amode : delete(+, ++, -), args : ["Tree0" : "A 2-3-4 tree", "Key" : "The key to delete", "Tree" : "The tree after deletion"], summary : "Delete a key/value pair from a tree.", fail_if : "Never fails.", resat : no, see_also : [remove / 4], desc : html("\t<P>\n\tIf the key Key appears in the tree Tree0, then remove it and its\n\tcorresponding value, resulting in the tree Tree.  If the key Key\n\tdoes not appear, Tree is simply bound to Tree0.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(init / 1, [amode : init(-), args : ["Tree" : "The new tree"], summary : "Initialise a new (empty) 2-3-4 tree.", fail_if : "Never fails.", resat : no, see_also : [is_empty / 1]]).
:- comment(insert / 4, [amode : insert(+, ++, ?, -), args : ["Tree0" : "A 2-3-4 tree", "Key" : "A key to insert", "Value" : "The value corresponding to Key", "Tree" : "The tree after insertion"], summary : "Insert a key/value pair into a tree, failing if the key already exists.", fail_if : "Fails if Key already appears in Tree0.", resat : no, see_also : [update / 4, set / 4], desc : html("\t<P>\n\tThis predicate inserts the key Key with corresponding value Value\n\tinto the tree Tree0, resulting in the tree Tree.  If the key Key is\n\talready in the tree, then the predicate fails.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(is_empty / 1, [amode : is_empty(+), args : ["Tree" : "A 2-3-4 tree"], summary : "Check whether a tree is empty.", fail_if : "Fails if Tree is not an empty tree.", resat : no, see_also : [init / 1]]).
:- comment(keys / 2, [amode : keys(+, -), args : ["Tree" : "A 2-3-4 tree", "KeyList" : "A list of all the keys from Tree"], summary : "Return all the keys from a tree.", fail_if : "Never fails.", resat : no, see_also : [values / 2], desc : html("\t<P>\n\tKeyList is a list of all the keys appearing in the tree Tree.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(lookup / 3, [amode : lookup(+, ++, ?), args : ["Tree" : "A 2-3-4 tree", "Key" : "A key to search for", "Value" : "The value corresponding to Key"], summary : "Search a tree for a key.", fail_if : "Fails if Value does not unify with the value corresponding to Key.", resat : no, see_also : [member / 3, search / 3], desc : html("\t<P>\n\tThis predicate searches the tree Tree for an entry with key Key.\n\tIf the key is found, then it attempts to unify the corresponding\n\tvalue with Value.  If the key is not found, then it aborts with\n\ta runtime error.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(lower_bound_lookup / 4, [amode : lower_bound_lookup(+, ++, ?, ?), args : ["Tree" : "A 2-3-4 tree", "SearchKey" : "A key to search for", "Key" : "The key found", "Value" : "The value corresponding to Key"], summary : "Search a tree for the smallest key no smaller than SearchKey.", fail_if : "Fails if Key and Value do not unify with the key and value found.", resat : no, see_also : [lower_bound_search / 4, upper_bound_search / 4, upper_bound_lookup / 4], desc : html("\t<P>\n\tThis predicate searches the tree Tree for the entry with the\n\tsmallest key which is no smaller than SearchKey.  If such a key is\n\tfound, then it attempts to unify it with Key and the corresponding\n\tvalue with Value.  If such a key is not found, then it aborts with\n\ta runtime error.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(lower_bound_search / 4, [amode : lower_bound_search(+, ++, ?, ?), args : ["Tree" : "A 2-3-4 tree", "SearchKey" : "A key to search for", "Key" : "The key found", "Value" : "The value corresponding to Key"], summary : "Search a tree for the smallest key no smaller than SearchKey.", fail_if : "Fails if there are no keys at least as large as SearchKey in Tree or if Key and Value do not unify with the key and value found.", resat : no, see_also : [lower_bound_lookup / 4, upper_bound_search / 4, upper_bound_lookup / 4], desc : html("\t<P>\n\tThis predicate searches the tree Tree for the entry with the\n\tsmallest key which is no smaller than SearchKey.  If such a key is\n\tfound, then it attempts to unify it with Key and the corresponding\n\tvalue with Value.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(member / 3, [amode : member(+, ?, ?), args : ["Tree" : "A 2-3-4 tree", "Key" : "A key from Tree", "Value" : "The value in Tree corresponding to Key"], summary : "Succeeds if Key and Value unify with a key/value pair from Tree.", fail_if : "Fails if Key and Value do not unify with a key/value pair from Tree.", resat : yes, see_also : [search / 3, lookup / 3], desc : html("\t<P>\n\tTries to unify Key and Value with key/value pairs from the tree Tree.\n\t</P>\n\t<P>\n\tIf Key and Value are variables and Tree is a 2-3-4 tree, then all\n\tmembers of the tree Tree are found on backtracking.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(remove / 4, [amode : remove(+, ++, ?, -), args : ["Tree0" : "A 2-3-4 tree", "Key" : "The key to remove", "Value" : "The value corresponding to Key", "Tree" : "The tree after removal"], summary : "Remove a key/value pair from a tree, failing if the key is not present.", fail_if : "Fails is Key does not appear in Tree0 or if Value does not unify with the corresponding value.", resat : no, see_also : [delete / 3, remove_smallest / 4], desc : html("\t<P>\n\tIf the key Key appears in the tree Tree0, then remove it and attempt\n\tto unify its corresponding value with Value.  Tree is Tree0 with the\n\tkey removed.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(remove_smallest / 4, [amode : remove_smallest(+, ?, ?, -), args : ["Tree0" : "A 2-3-4 tree", "Key" : "The key removed", "Value" : "The value corresponding to Key", "Tree" : "The tree after removal"], summary : "Remove the smallest key and its corresponding value from a tree.", fail_if : "Fails if Tree0 is empty or if Key and Value do not unify with the key and value removed.", resat : no, see_also : [remove / 4], desc : html("\t<P>\n\tRemoves the smallest key in the tree Tree0 (resulting in the\n\ttree Tree), and attempts to unify the removed key with Key and \n\tits corresponding value with Value.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(search / 3, [amode : search(+, ++, ?), args : ["Tree" : "A 2-3-4 tree", "Key" : "A key to search for", "Value" : "The value corresponding to Key"], summary : "Search a tree for a key.", fail_if : "Fails if Key does not appear in Tree or if Value does not unify with the corresponding value found.", resat : no, see_also : [member / 3, lookup / 3], desc : html("\t<P>\n\tThis predicate searches the tree Tree for an entry with key Key.\n\tIf the key is found, then it attempts to unify the corresponding\n\tvalue with Value.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(set / 4, [amode : set(+, ++, ?, -), args : ["Tree0" : "A 2-3-4 tree", "Key" : "A key to set", "Value" : "The value corresponding to Key", "Tree" : "The tree after setting"], summary : "Update the value corresponding to a key in a tree, inserting the key if it doesn't exist already.", fail_if : "Never fails.", resat : no, see_also : [insert / 4, update / 4], desc : html("\t<P>\n\tIf the key Key already exists in the tree Tree0, then this predicate\n\tupdates the corresponding value to be Value.  Otherwise it inserts\n\tthe key Key into the tree with value Value.  The resulting tree is\n\tTree.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(tree234_to_assoc_list / 2, [amode : tree234_to_assoc_list(+, -), args : ["Tree" : "A 2-3-4 tree", "AssocList" : "A list of the key-value pairs from Tree"], summary : "Converts a tree into an association list.", fail_if : "Never fails.", resat : no, see_also : [assoc_list_to_tree234 / 2], desc : html("\t<P>\n\tAssocList is a list containing the key/value pairs from the tree\n\tTree, in the form Key-Value.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(update / 4, [amode : update(+, ++, ?, -), args : ["Tree0" : "A 2-3-4 tree", "Key" : "A key to update", "Value" : "The value corresponding to Key", "Tree" : "The tree after updating"], summary : "Update the value corresponding to a key in a tree.", fail_if : "Fails if Key does not appear in Tree0.", resat : no, see_also : [insert / 4, set / 4], desc : html("\t<P>\n\tIf the key Key already exists in the tree Tree0, then this predicate\n\tupdates the corresponding value to be Value.  The resulting tree is\n\tTree.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(upper_bound_lookup / 4, [amode : upper_bound_lookup(+, ++, ?, ?), args : ["Tree" : "A 2-3-4 tree", "SearchKey" : "A key to search for", "Key" : "The key found", "Value" : "The value corresponding to Key"], summary : "Search a tree for the largest key no larger than SearchKey.", fail_if : "Fails if Key and Value do not unify with the key and value found.", resat : no, see_also : [lower_bound_search / 4, lower_bound_lookup / 4, upper_bound_search / 4], desc : html("\t<P>\n\tThis predicate searches the tree Tree for the entry with the\n\tlargest key which is no larger than SearchKey.  If such a key is\n\tfound, then it attempts to unify it with Key and the corresponding\n\tvalue with Value.  If such a key is not found, then it aborts with\n\ta runtime error.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(upper_bound_search / 4, [amode : upper_bound_search(+, ++, ?, ?), args : ["Tree" : "A 2-3-4 tree", "SearchKey" : "A key to search for", "Key" : "The key found", "Value" : "The value corresponding to Key"], summary : "Search a tree for the largest key no larger than SearchKey.", fail_if : "Fails if there are no keys at least as large as SearchKey in Tree or if Key and Value do not unify with the key and value found.", resat : no, see_also : [lower_bound_search / 4, lower_bound_lookup / 4, upper_bound_lookup / 4], desc : html("\t<P>\n\tThis predicate searches the tree Tree for the entry with the\n\tlargest key which is no larger than SearchKey.  If such a key is\n\tfound, then it attempts to unify it with Key and the corresponding\n\tvalue with Value.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
:- comment(values / 2, [amode : values(+, -), args : ["Tree" : "A 2-3-4 tree", "ValueList" : "A list of all the values from Tree"], summary : "Return all the values from a tree.", fail_if : "Never fails.", resat : no, see_also : [values / 2], desc : html("\t<P>\n\tValueList is a list of all the values appearing in the tree Tree.\n\t</P>\n\t<P>\n\tThis predicate should only be called with trees created by other\n\tpredicates from the tree234 module.\n\t</P>\n\t")]).
